package cc.yaomm.common.basic.util;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import ma.glasnost.orika.CustomConverter;
import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.converter.ConverterFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import ma.glasnost.orika.metadata.ClassMapBuilder;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * <p>@Description : 基于Orika异构对象深层映射.</p>
 * <p>@Author : Zhangbin.Liu </p>
 * <p>@Date : 2019/8/29 18:04 </p>
 */
public class BeanUtils {

    private static Set<CustomConverter> converters;

    private static Map<String, CustomConverter> converterMap;

    private static MapperFacade mapper;

    static {
        converters = Sets.newHashSetWithExpectedSize(5);
        converterMap = Maps.newHashMapWithExpectedSize(5);
        mapper = createFacade();
    }

    public static <SOURCE, DESTINATION> DESTINATION map(SOURCE source, Class<DESTINATION> destinationClass) {
        return mapper.map(source, destinationClass);
    }

    public static <SOURCE, DESTINATION> List<DESTINATION> mapList(Iterable<SOURCE> sourceList,
                                                                  Class<DESTINATION> destinationClass) {
        return mapper.mapAsList(sourceList, destinationClass);
    }

    private static MapperFactory createFactory() {
        MapperFactory factory = new DefaultMapperFactory.Builder().build();

        ConverterFactory converterFactory = null;
        if (!CollectionUtils.isEmpty(converters)) {
            converterFactory = factory.getConverterFactory();

            for (CustomConverter converter : converters) {
                if (null == converter) {
                    continue;
                }

                converterFactory.registerConverter(converter);
            }
        }

        if (!CollectionUtils.isEmpty(converterMap)) {
            if (null == converterFactory) {
                converterFactory = factory.getConverterFactory();
            }

            for (Map.Entry<String, CustomConverter> entry : converterMap.entrySet()) {
                if (null == entry) {
                    continue;
                }

                converterFactory.registerConverter(entry.getKey(), entry.getValue());
            }
        }

        return factory;
    }

    private static MapperFacade createFacade() {
        return createFactory().getMapperFacade();
    }

    @Deprecated
    public static <SOURCE, DESTINATION> MapperFacade createFacade(Class<SOURCE> sourceClass,
                                                                  Class<DESTINATION> destinationClass, String... ignoreProperties) {

        MapperFactory factory = createFactory();

        if (null != ignoreProperties && ArrayUtils.isNotEmpty(ignoreProperties)) {
            ClassMapBuilder<?, DESTINATION> builder = factory.classMap(sourceClass, destinationClass);
            for (String ignoreProperty : ignoreProperties) {
                if (StringUtils.isBlank(ignoreProperty)) {
                    continue;
                }

                builder.exclude(ignoreProperty);
            }

            builder.byDefault().register();
        }

        return factory.getMapperFacade();
    }

    public static void addConverter(CustomConverter converter) {
        converters.add(converter);
    }

    public static MapperFacade getMapper() {
        return mapper;
    }

}